Skip to main content

Coding Conventions Guidelines

Folders and files organization

Folders hierarchy

✔️ DO Respect the project hierarchy

root
+- build
+- docs
| +- diagrams
| | +- uml
| +- pictures
| +- tutorials
| +- movies
+- examples
| +- xtd.forms
| | +- application
| | +- common_dialogs
| | +- components
| | +- ...
| +- ...
+- locale
| +- af
| +- am
| +- ...
+- resources
| + countries
| + cursors
| + ...
+- scripts
| +- cmake
| +- install
| +- ...
+- src
| +- xtd.forms
| | +- include
| | | +- xtd
| | | +- forms
| | | | +- layout
| | | | +- ...
| | |  +- ...
| | +- src
| | +- xtd
| | +- forms
| | | +- layout
| | | +- ...
| |   +- ...
| +- ...
+- tests
| +- xtd.forms.manual_tests
| +- xtd.forms.unit_tests
| | +- xtd
| | +- forms
| | | +- ...
| | +- ...
| +- ...
+- themes
+- tools
+- guidgen
+- guidgen-gui
+- ...
  • root folder is the project folder where xtd project was extracted or cloned.
  • root/build folder contains the build result. This folder will automatically created during the installation.
  • root/docs folder contains markdown documentations.
  • root/docs/diagrams folder contains the diagrams used to illustrate the markdown documentation and website.
  • root/docs/diagrams/uml folder contains the UML diagrams used to illustrate the markdown documentation and website.
  • root/docs/pictures folder contains the pictures used to illustrate the markdown documentation and website.
  • root/docs/tutorials folder contains the xtd tutorials.
  • root/docs/movies folder contains the movies used to demonstrate how to use xtd.
  • root/examples folder contains examples to show how to used xtd libraries organized by library and example theme.
  • root/locale folder contains rlocale files organized by language.
  • root/resources folder contains resource files organized by theme.
  • root/scripts folder contains developer helper scripts.
  • root/scripts/appveyor folder contains scripts needed by appveyor CI.
  • root/scripts/cmake folder contains scripts needed by cmake.
  • root/scripts/install folder contains installation scripts.
  • root/scripts/travis folder contains scripts needed by travis CI.
  • root/src folder contains source files organized by library.

For each library the hierarchy is identical :

root/xtd.library.name/include folder contains include files for xtd.library_name library.

root/xtd.library.name/include/namespace1/namespace2/... folder contains include files for xtd.library.name library organized by namespace.

root/xtd.library.name/src folder contains source files for xtd.library.name library.

root/xtd.library.name/src/namespace1/namespace2/... folder contains source files for xtd.library.name library organized by namespace.

root/tests folder contains tests organized by library and namespaces.

root/themes folder contains default css theme files.

root/tools folder contains xtd tools.

For example, the root/src/xtd.forms folder contains xtd library source files and the root/src/xtd.forms.native.win32 folder contains xtd.forms.native.win32 library source files.

For example, the root/tests/xtd.forms.unit_tests contains xtd.forms library unit tests.

For example, if a xtd.forms library header file contains :

#pragma once

#include <xtd/event_args.h>
#include "close_reason.h"

namespace xtd {
namespace forms {
class form_closed_event_args : public event_args {
public:
form_closed_event_args() = default;
form_closed_event_args(forms::close_reason close_reason) : close_reason_(close_reason) {};

/// @cond
form_closed_event_args(const form_closed_event_args& form_closed_event_args) = default;
form_closed_event_args& operator =(const form_closed_event_args& form_closed_event_args) = default;
/// @endcond

forms::close_reason close_reason() const {return close_reason_;}

private:
forms::close_reason close_reason_ = forms::close_reason::none;
};
}
}

The file will be in root/src/xtd.forms/include/xtd/forms/ path

File names

✔️ DO Name file with same name of the class, struct, enum, delegate or event that contains.

For example, if file contains :

#pragma once

#include <xtd/event_handler.h>
#include "form_closed_event_args.h"

namespace xtd {
namespace forms {
template<typename type_t>
using form_closed_event_handler = delegate<void(const type_t& sender, const form_closed_event_args& e)>;
}
}

The file will be named to form_closed_event_handler.h.

File extensions

✔️ DO Use .h for header files.

✔️ DO Use .cpp for source files.

Diagrams

✔️ DO Diagrams are generated by Draw.IO Desktop. Draw.IO Desktop is a Google Chrome extension.

UML diagrams

✔️ DO UML diagrams are generated by plantUML.

Editor

✔️ DO Replace tab character with double spaces in your editor or IDE properties.

✔️ DO Use two space for indentation.

class my_control : public xtd::forms::control {
public:
my_control() = default;
my_control(const my_control&) = default;
};

Order of parts in a class or struct declarations

First order is on protection type :

✔️ DO Put public members in first.

✔️ DO Put protected members in second.

✔️ DO And finally put private members at least.

Second order for each protection type :

✔️ DO Put inner classes and structs in first.

✔️ DO Put constructors / Destructor / Copy operator in seconds.

✔️ DO Put properties in third.

✔️ DO Put events in fourth.

✔️ DO Put methods in fifth.

✔️ DO And put members in last.

✔️ DO Organize properties, events, methods and member in alphabetic order.

class my_control : public xtd::forms::control {
public:
my_control() = default;
my_control(const my_control&) = default;
my_control& my_control& operator =(const my_control& my_control);

const std::string base_name() const {return base_name_;}
intptr_t handle() const {return handle_;}

xtd::event<my_control, event_handler<xtd::forms::control>> name_changed;

std::string to_string() const override {return name_generator();}

protected:
virtual std::string name_generator() const {return base_name_;}

intptr_t handle_ = 0;

private:
my_control(intptr_t handle);

std::string base_name_ = "BaseName";
};

#define

❌ DO NOT Use #define for any good or bad reason.

✔️ DO But instead use static constexpr or static const for constants.

header file :
class my_class {
public:
static constexpr int max_value = std::numeric_limits<int>::max();
static const xtd::version min_version;
};
source file :
const xtd::version my_class::min_version(2, 1, 0);

✔️ Do All macro can be replaced by template method.

class math {
public:
math() = delete;
// equivalent : #define max(value1, value2) (value1 >= value2 ? value1 : value2)
template<typename T>
static T max(T value1, T value2) {return value1 >= value2 ? value1 : value2;}
};

Globals

Global methods

❌ DO NOT Use global methods. All methods are in class. If necessary creates container class like xtd::forms:cursors to group static methods.

global variables

❌ DO NOT Use global variables. All variables are in class. If necessary a global or static variable can create in a source files (.cpp) but it can't visible in the header file (.h).

✔️ DO Uses factory_method, builder or singleton patterns to create unique object.

Comments

✔️ DO Using always simple line comment // instead block comment /* */

// This is my
// multiline comment
int x = 3;

Documentation

The documentation is generated by Doxygen.

✔️ DO Write Doxygen documentation only in header file (.h).

✔️ DO All documentation comment must start by triple slash ///

/// @brief my_class do something
class my_class {
};

✔️ DO Doxygen command start with at-sign @

/// @brief my_func do something
/// @param name A string that contains the name.
/// @remarks The name must be begin by a uppercase; otherwise std::invalid_argument throws.
/// @exception std::invalid_argument name not started by uppercase.
void my_func(const std::string& name) {
};

This example of doxygen documented class (application_context.h) shows some doxygen commands:

#pragma once
#include "form.h"

/// @brief The xtd namespace contains all fundamental classes to access Hardware, Os, System, and more.
namespace xtd {
/// @brief The xtd::forms namespace contains classes for creating Windows-based applications that take full advantage of the rich user interface features available in the Microsoft Windows operating system, Apple macOS and Linux like Ubuntu operating system.
namespace forms {
/// @cond
class application;
/// @endcond

/// @brief Specifies the contextual information about an application thread.
/// @remarks You can use the application_context class to redefine the circumstances that cause a message loop to exit. By default, the application_context listens to the closed event on the application's main form, then exits the thread's message loop.
/// @par Examples
/// The following code example demonstrates the use of application and application_context classes.
/// @include application_context.cpp
class application_context {
public:
/// @brief Initializes a new instance of the application_context class with no context.
application_context() = default;
/// @brief Initializes a new instance of the application_context class with the specified Form.
/// @param main_form The main form of the application to use for context.
/// @remarks If on_main_form_closed is not overridden, the message loop of the thread terminates when main_form is closed.
explicit application_context(const form& main_form) {this->main_form(main_form);}

/// @cond
virtual ~application_context() {
if (main_form_ != nullptr) main_form_->handle_destroyed -= {*this, &application_context::on_main_form_closed};
}
/// @endcond

/// @brief Gets the form to use as context.
/// @return The form to use as context.
/// @remarks This property determines the main form for this context. This property can change at any time. If on_main_form_closed is not overridden, the message loop of the thread terminates when the main_form parameter closes.
const form& main_form() const {return *main_form_;}
/// @brief Gets or sets the Form to use as context.
/// @return The form to use as context.
/// @remarks This property determines the main form for this context. This property can change at any time. If on_main_form_closed is not overridden, the message loop of the thread terminates when the main_form parameter closes.
form& main_form() {return *main_form_;}
/// @brief Sets the Form to use as context.
/// @param main_form The form to use as context.
/// @remarks This property determines the main form for this context. This property can change at any time. If on_main_form_closed is not overridden, the message loop of the thread terminates when the main_form parameter closes.
void main_form(const form& main_form) {
if (main_form_ != nullptr) main_form_->handle_destroyed -= {*this, &application_context::on_main_form_closed};
main_form_ = const_cast<form*>(&main_form);
main_form_->handle_destroyed += {*this, &application_context::on_main_form_closed};
}

/// @brief Gets an object that contains data about the control.
/// @return A std::any that contains data about the control. The default is empty.
/// @remarks Any type of class can be assigned to this property.
/// @remarks A common use for the tag property is to store data that is closely associated with the control. For example, if you have a control that displays information about a customer, you might store a data_set that contains the customer's order history in that control's tag property so the data can be accessed quickly.
std::any tag() const {return tag_;}
/// @brief Sets an object that contains data about the control.
/// @param tag A std::any that contains data about the control. The default is empty.
/// @remarks Any type of class can be assigned to this property.
/// @remarks A common use for the tag property is to store data that is closely associated with the control. For example, if you have a control that displays information about a customer, you might store a data_set that contains the customer's order history in that control's tag property so the data can be accessed quickly.
void tag(std::any tag) {tag_ = tag;}

/// @brief Occurs when the message loop of the thread should be terminated, by calling exit_thread().
event<application_context, event_handler<const application_context&>> thread_exit;

/// @brief Terminates the message loop of the thread.
/// @remarks This method calls exit_thread_core.
/// @note exit_thread and exit_thread_core do not actually cause the thread to terminate. These methods raise the thread_exit event to which the Application object listens. The Application object then terminates the thread.
void exit_thread() {exit_thread_core();}

protected:
/// @brief Terminates the message loop of the thread.
/// @remarks This method is called from exit_thread.
/// @note exit_thread and exit_thread_core do not actually cause the thread to terminate. These methods raise the thread_exit event to which the Application object listens. The Application object then terminates the thread.
virtual void exit_thread_core() {thread_exit(*this, event_args::empty);}

/// @brief Calls ExitThreadCore(), which raises the ThreadExit event.
/// @param sender The object that raised the event.
/// @param e The event_args that contains the event data.
/// @remarks The default implementation of this method calls exit_thread_core.
virtual void on_main_form_closed(const control& sender, const event_args& e) {
if (!main_form_->recreating_handle()) {
main_form_->handle_destroyed -= {*this, &application_context::on_main_form_closed};
exit_thread_core();
}
}

private:
/// @cond
friend class application;
/// @endcond
form* main_form_ = nullptr;
std::any tag_;
};
}
}

For more commands see Doxygen Special commands and for more informations see Doxygen Manual.

Indentation

✔️ DO Indent block contents

namespace test {
class aclass {
void method() {
int x;
int y;
}
};
}

❌ DO NOT Indent open and close braces

class aclass {
int afield;

void method() {
}
};

❌ DO NOT Indent switch sections

class aclass {
void method(int x) {
switch (x) {
case 1:
break;
}
}
};

✔️ DO Indent case sections

class aclass {
void method(int x) {
switch (x) {
case 1:
break;
}
}
};

❌ DO NOT Indent label

class test {
void method() {
label:
console::write_line("Hello World");
}
};

New lines

New line options for braces

❌ DO NOT Place open brace on new line for types

class example {
};

❌ DO NOT Place open brace on new line for methods

void example() {
}

❌ DO NOT Place open brace on new line for lambda expressions

void example() {
auto del = [](int i, int j) {
};
}

❌ DO NOT Place open brace on new line for control blocks

void example() {
if (true) {
}
}

❌ DO NOT Place open brace on new line for object initializers

void example() {
std::vector<int> array_list {
42, 24, 84
};
}

New line options for keywords

❌ DO NOT Place "else" on new line

void example() {
if (true) {
// ...
} else {
// ...
}
}

❌ DO NOT Place "catch" on new line

void example() {
try {
// ...
} catch(...) {
// ...
}
}

New line options for expressions

❌ DO NOT Place member object initializers on new line

void example() {
xtd::drawing::point p {
10, 24
};
}

Spacing

Set spacing for method declarations

❌ DO NOT Insert space between method name and its opening parenthesis

void example() {
}

❌ DO NOT Insert space within argument list parentheses

void example(int i, int j) {
}

❌ DO NOT Insert space within empty argument list parentheses

void example() {
}

Set spacing for method calls

❌ DO NOT Insert space between method name and its opening parenthesis

void example() {
test();
}

❌ DO NOT Insert space within argument list parentheses

void example() {
test(int i, int j);
}

❌ DO NOT Insert space within empty argument list parentheses

void example() {
test();
}

Set other spacing options

✔️ DO Insert space after keywords in control flow statements

void example() {
if (condition) {
}
}

❌ DO NOT Insert space within parentheses of expressions

void example() {
i = (5 + 3) * 2;
}

❌ DO NOT Insert space within parentheses of type casts

void example() {
test = (const itest&)o;
}

❌ DO NOT Insert space within parentheses of control flow statements

void example() {
if (condition) {
}
}

❌ DO NOT Insert space after casts

void example() {
test = (const itest&)o;
}

✔️ DO Insert space in declaration statements

void example() {
int x = 5;
}

Set spacing for square brackets

❌ DO NOT Insert space before open square bracket

void example() {
i[5] = 3;
}

❌ DO NOT Insert space within empty square brackets

void example() {
test(int[] {1, 2});
}

❌ DO NOT Insert space within square brackets

void example() {
i[5] = 3;
}

Set spacing for brackets

✔️ DO Insert space after colon for base or interface in type declaration

class foo : public bar {
}

✔️ DO Insert space after comma

void example() {
int i = 0, j = 15;
}

❌ DO NOT Insert space after dot

void example() {
foo.bar().test();
}

❌ DO NOT Insert space after structure or class dereference

void example() {
foo->bar()->test();
}

✔️ DO Insert space after semicolon in "for" statement

void example() {
for (int i = 0; i < 10; i++) {
}
}

✔️ DO Insert space before colon for base or interface in type declaration

class foo : public bar {
}

❌ DO NOT Insert space before dot

void example() {
foo.bar().test();
}

❌ DO NOT Insert space before structure or class dereference

void example() {
foo->bar()->test();
}

❌ DO NOT Insert space before semicolon in "for" statement

void example() {
for (int i = 0; i < 10; i++) {
}
}

✔️ DO Set spacing for operators

void example() {
i = (5 + 3) * 2;
}

See also